package cn.lingyangwl.agile.member.service;

import cn.hutool.core.collection.CollUtil;
import cn.lingyangwl.agile.common.security.utils.SecurityUtils;
import cn.lingyangwl.agile.member.assembly.MemberAddressAssembly;
import cn.lingyangwl.agile.member.mapper.MemberAddressMapper;
import cn.lingyangwl.agile.member.model.entity.MemberAddress;
import cn.lingyangwl.agile.member.model.rqrs.address.AddressResp;
import cn.lingyangwl.agile.member.model.rqrs.address.AddressSaveReq;
import cn.lingyangwl.agile.member.model.rqrs.address.AddressSaveThirdReq;
import cn.lingyangwl.agile.model.constants.*;
import cn.lingyangwl.agile.system.SystemApi;
import cn.lingyangwl.agile.system.constants.SystemCons.*;
import cn.lingyangwl.agile.system.model.entity.*;
import cn.lingyangwl.agile.tenant.core.*;
import cn.lingyangwl.framework.tool.core.exception.BizException;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.service.IService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * 会员订单地址
 *
 * @author shenguangyang
 */
@Slf4j
@Service
public class MemberAddressServiceImpl extends ServiceImpl<MemberAddressMapper, MemberAddress>
    implements IService<MemberAddress>, MemberAddressService {

    @Resource
    private MemberAddressAssembly addressAssembly;
    @Resource
    private SystemApi systemApi;
    
    @Override
    @Tenant(level = DataIsolateLevel.MAIN)
    public List<AddressResp> listAddress() {
        Long userId = SecurityUtils.getUserId();
        LambdaQueryWrapper<MemberAddress> lqw = MemberAddress.lqw()
            .eq(Objects.nonNull(userId), MemberAddress::getUserId, userId)
            .orderByDesc(MemberAddress::getIsDefault);
        List<MemberAddress> list = this.list(lqw);
        return list.stream().map(addressAssembly::toAddressResp).collect(Collectors.toList());
    }

    @Override
    @Tenant(level = DataIsolateLevel.MAIN)
    public AddressResp getAddress(Long userId, Long id) {
        LambdaQueryWrapper<MemberAddress> lqw = MemberAddress.lqw()
            .eq(MemberAddress::getId ,id)
            .eq(Objects.nonNull(userId), MemberAddress::getUserId, userId);
        MemberAddress entity = this.getOne(lqw);
    	return addressAssembly.toAddressResp(entity);
    }

    @Override
    @Tenant(level = DataIsolateLevel.MAIN)
    public boolean saveAddress(AddressSaveReq req) {
        LambdaQueryWrapper<MemberAddress> lqw = MemberAddress.lqw()
            .eq(MemberAddress::getUserId, SecurityUtils.getUserId())
            .eq(MemberAddress::getIsDefault, true);
        MemberAddress entity = addressAssembly.toAddress(req);
        if (this.count(lqw) == 0) {
            entity.setIsDefault(true);
        }
        entity.setUserId(SecurityUtils.getUserId());
    	return this.save(entity);
    }

    @Override
    @Tenant(level = DataIsolateLevel.MAIN)
    public boolean updateAddress(AddressSaveReq req) {
        MemberAddress entity = addressAssembly.toAddress(req);
        entity.setUserId(SecurityUtils.getUserId());
    	return this.updateById(entity);
    }

    @Override
    @Tenant(level = DataIsolateLevel.MAIN)
    public boolean deleteAddress(Long id) {
        LambdaQueryWrapper<MemberAddress> lqw = MemberAddress.lqw()
            .eq(MemberAddress::getId ,id)
            .eq( MemberAddress::getUserId, SecurityUtils.getUserId());
    	return this.remove(lqw);
    }
    
    @Override
    @Tenant(level = DataIsolateLevel.MAIN)
    public boolean batchDeleteAddress(List<Long> ids) {
        if (CollUtil.isEmpty(ids)) {
            return false;
        }
        LambdaQueryWrapper<MemberAddress> lqw = MemberAddress.lqw()
            .in(MemberAddress::getId ,ids)
            .eq( MemberAddress::getUserId, SecurityUtils.getUserId());
        return this.remove(lqw);
    }

    @Override
    @Tenant(level = DataIsolateLevel.MAIN)
    @Transactional(rollbackFor = Exception.class)
    public void setDefault(Long id) {
        LambdaQueryWrapper<MemberAddress> lqw = MemberAddress.lqw()
            .eq(MemberAddress::getUserId, SecurityUtils.getUserId())
            .eq(MemberAddress::getIsDefault, true);
        MemberAddress oldDefaultAddress = this.getOne(lqw);
        if (Objects.nonNull(oldDefaultAddress)) {
            oldDefaultAddress.setIsDefault(false);
            this.updateById(oldDefaultAddress);
        }

        LambdaUpdateWrapper<MemberAddress> luw = MemberAddress.luw()
            .eq(MemberAddress::getUserId ,SecurityUtils.getUserId())
            .eq(MemberAddress::getId, id).set(MemberAddress::getIsDefault, true);
        if (!this.update(luw)) {
            throw new BizException("设置默认地址失败");
        }

    }

    @Override
    @Tenant(level = DataIsolateLevel.MAIN)
    public AddressResp getDefault() {
        LambdaQueryWrapper<MemberAddress> lqw = MemberAddress.lqw()
            .eq(MemberAddress::getUserId, SecurityUtils.getUserId())
            .eq(MemberAddress::getIsDefault, true);
        return addressAssembly.toAddressResp(this.getOne(lqw));
    }

    @Override
    @Tenant(level = DataIsolateLevel.MAIN)
    public void saveThreeParties(AddressSaveThirdReq req) {
        req.setUserId(SecurityUtils.getUserId());

        // step 获取区域id
        List<String> types = new ArrayList<>();
        types.add(AreaType.PROVINCE);
        types.add(AreaType.CITY);
        types.add(AreaType.REGION);

        List<String> areaNames = new ArrayList<>();
        areaNames.add(req.getCityName());
        areaNames.add(req.getProvinceName());
        areaNames.add(req.getRegionName());
        Map<String, SysArea> areaMap = systemApi.listAreaByNames(types, areaNames).stream()
            .collect(Collectors.toMap(e -> e.getAreaType() + e.getAreaName(), Function.identity()));

        MemberAddress address = addressAssembly.toAddress(req);
        Long cityId = Optional.ofNullable(areaMap.get(AreaType.CITY + req.getCityName()))
            .map(e -> Long.parseLong(e.getId())).orElseThrow(() -> new BizException("城市不存在"));
        Long provinceId = Optional.ofNullable(areaMap.get(AreaType.PROVINCE + req.getProvinceName()))
            .map(e -> Long.parseLong(e.getId())).orElseThrow(() -> new BizException("省份不存在"));
        Long regionId = Optional.ofNullable(areaMap.get(AreaType.REGION + req.getRegionName()))
            .map(e -> Long.parseLong(e.getId())).orElseThrow(() -> new BizException("区县不存在"));

        address.setCityId(cityId);
        address.setProvinceId(provinceId);
        address.setRegionId(regionId);

        // step 判断有没有默认地址, 没有就设置一个
        LambdaQueryWrapper<MemberAddress> lqw = MemberAddress.lqw()
            .eq(MemberAddress::getUserId, SecurityUtils.getUserId())
            .eq(MemberAddress::getIsDefault, true);
        if (this.count(lqw) == 0) {
            address.setIsDefault(true);
        }
        this.save(address);
    }
}
